#ifndef __CACHE_H__
#define __CACHE_H__

#include <pthread.h>

#define FRAME_FLAG_IUNIT    (1<<0)
#define FRAME_FLAG_PUNIT    (1<<1)
#define FRAME_FLAG_AUDIO    (1<<2)
#define FRAME_FLAG_CTCMD    (1<<3)

#define CACHE_FLAG_STREAM   (1<<16)
#define CACHE_FLAG_TODEVD   (1<<17)
#define CACHE_FLAG_TOAPPD   (1<<18)

#define MAX_FRAME_RATE	    15 
#define MAX_READER_CNT	    100

#define CACHE_CLEAR_FLAG    0xff

enum cache_type
{
    CACHE_TYPE_STREAM = 0,
    CACHE_TYPE_TODEVD,
    CACHE_TYPE_TOAPPD,
    CACHE_TYPE_MAX
};

typedef struct frame_unit
{
    int flag;
    int next_i_pos;
    int reader_id;
    unsigned int len;
    unsigned char *paddr;
}st_frame_unit;


typedef struct cache_attr
{
    pthread_rwlock_t rwlock;
    unsigned int data_cache_size;
    unsigned int frame_unit_size;
    unsigned char *data_cache_start; // malloced
    unsigned char *data_cache_end;
    st_frame_unit *frame_unit_array; // malloced
    int reader_cnt;
    int write_funit_pos; // the next frame unit pos to write  
    int last_iframe_pos;
    int reader_funit_pos[MAX_READER_CNT];
}st_cache_attr;

typedef struct cache_index_item
{
    char devid[32];
    st_cache_attr *pcache;
}st_cache_index_item;

struct cache_index
{
    pthread_mutex_t lock;
    unsigned int size; // capacity
    unsigned int num; // index count number
    st_cache_index_item index[];
};

// malloc index memory
int cache_index_init(int max_index);
int cache_index_exit(void);
int cache_index_add2(const char *devid,unsigned int data_cache_size,unsigned int frame_unit_size);

int cache_index_add(const char *devid);
int cache_index_del(const char *devid);

/*
 * @param[in] rid reader ID, Device Reader ID = 0, ALL Reader = -1, Client Reader = 0~MAX_READER_CNT-1
 * return -1 if has error, 0 if write ok; return CACHE_CLEAR_FLAG when reader count is 0.
 */
int cache_write_frame(const char *devid,int rid,unsigned char *buf,int len,int flag);

/*
 * read a frame from cache of the assigned device
 *
 * @param[in] devid device ID to index frame cache
 * @param[in] rid the reader id, 0~MAX_READER_CNT, return by cache_add_reader API,
 * Device Reader = 0.
 * @param[out] buf the frame read from cache
 * @param[in] size the buf capacity to put frame
 * @param[in,out] flag the frame flag mask used to filter frame, 0xffffffff - any frame,
 *  when read frame success, @flag would be set to the read-frame flag.
 * @ret	return -1 if read frame fail, return 0 if cache is empty, return frame size if ok.
 */
int cache_read_frame(const char *devid,int rid,unsigned char *buf,int size,int *flag);

/* return reader ID */
int cache_add_reader(const char *devid);
int cache_del_reader(const char *devid,int rid);

#endif

